home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_100
/
111_01
/
bcanlyz.c
< prev
next >
Wrap
Text File
|
1985-08-19
|
10KB
|
600 lines
/*
HEADER: ;
TITLE: Expression evaluator;
VERSION: 1.0;
DESCRIPTION: "Auxiliary file for BC.C. May be useful in other C programs.
Evaluates arithmetic and logic expressions. Takes a string
expression as argument, and returns the value of the
expression, an integer, 0 through 65535.";
KEYWORDS: Arithmetic, logical, expression, evaluator, calculator;
SYSTEM: CP/M-80;
FILENAME: BCANLYZ.C;
WARNINGS: "Limited to integers, 0 to 65535.";
SEE-ALSO: BC.C, BC.DOC, BCDEF.H, BCREVIEW.DOC;
AUTHORS: Jan Larsson;
COMPILERS: BDS C;
*/
/*********************************************************************
Delimiters: \0, \n, \f, ,, ), ;
Operators: +, -, *, /, <, >, %, &, |, ^, mod, and, or, xor, shl, shr
Unary operators: +, -, ~, not
(c) 1981 Jan Larsson
**********************************************************************/
#include "bcdef.h"
unsigned anlyz( s )
char *s ;
{
int nesting, *depth ;
char *p ;
int n, left, right ;
unsigned result ;
depth = &nesting ;
*depth = 0 ;
p = s ; right = left = 0 ;
while(*p != EOL){
if(*p == LPAREN)left++ ;
if(*p == RPAREN)right++ ;
p++ ;
}
if(right > left)
printf("%4u: Missing left parenthesis in expression.\n",line());
else if(right < left)
printf("%4u: Missing right parenthesis in expression.\n",line());
else return( anlyz2( s ) );
return( FALSE );
}
/*
O.k. evaluate a simple expression <value> <operator> <value> .
If a parenthesis occurs anlyz2 does a recursive call on itself
to evaluate it first. No operator precedence is implemented, just
simple left --> right evaluation.
*/
unsigned anlyz2( s, depth )
char *s ;
int *depth ;
{
char error, op, *skipsp(), *skipexpr() ;
char *skiptok(), *skipop(), gettop() ;
char unary, isunary() ;
unsigned rval, lval, gettok() ;
error = FALSE ;
*depth++ ;
s = skipsp( s );
if(eoe(*s)){aerror(0);*depth--;return(0);}
while(!eoe(*s)){
unary = isunary( s );
if(unary != FALSE)s = skipop( s );
if(*s == LPAREN){ lval = anlyz2( s+1 );
s = skipexpr( s );}
else { lval = gettok( s ); s = skiptok( s ); }
if(unary != FALSE){
switch (unary) {
case PLUS : break ;
case MINUS : lval = - lval ; break ;
case NOT : lval = ~ lval ; break ;
case SNOT : lval = ~ lval ; break ;
}
unary = FALSE ;
}
if(!eoe(*s)){
for(;;){
if(eoe(*s)){ aerror( 1 ) ; break ;}
op = gettop( s ); s = skipop( s );
if(eoe(*s)){ aerror(2); break ;}
unary = isunary( s );
if(unary != FALSE)s = skipop( s );
if(*s == LPAREN){ rval = anlyz2( s+1 ); s = skipexpr( s );}
else { rval = gettok( s ); s = skiptok( s );}
if(unary != FALSE){
switch (unary) {
case MINUS : rval = - rval ; break ;
case SNOT : rval = ~ rval ; break ;
case PLUS : break ;
case NOT : rval = ~ rval ; break ;
}
unary = FALSE ;
}
lval = calc( lval, op, rval );
if(eoe(*s))break;
}
}
}
*depth-- ;
return( lval );
}
/*
Return true if c is an end_of_expression delmiter, else false
*/
eoe( c )
char c ;
{
switch (c) {
case NEWLINE :
case FORMFEED :
case EOL :
case RPAREN :
case COMMA :
case SEMICOLON : return( TRUE );
default : return( FALSE );
}
}
/*
Return TRUE if c is a space character (to be ignored), else FALSE
*/
spc( c )
char c ;
{
switch (c) {
case SPACE :
case COLON :
case TAB :
case SPACE : return( TRUE );
default : return( FALSE );
}
}
/*
Return TRUE if c is a legal operator, else FALSE
*/
op( c )
char c ;
{
switch (c) {
case PLUS :
case MINUS :
case MULT :
case DIV :
case NOT :
case XOR :
case AND :
case SHL :
case SHR :
case MOD :
case OR : return( TRUE );
default : return( FALSE );
}
}
/*
Her we take a pointer as argument, increments it until it
finds the next non-space character, then return pointer value.
*/
char *skipsp( s )
char *s ;
{
while(spc( *s ) && !eoe(*s))s++ ;
return( s );
}
/*
Skiptok takes a pointer as argument, returns a pointer to the first
position after the current token (numeric constant, symbol etc.)
*/
char *skiptok( s )
char *s ;
{
s = skipsp( s );
while(!spc( *s ) && !op( *s ) && !eoe( *s ) && *s != LPAREN)s++ ;
s = skipsp( s );
return( s );
}
/*
Skipop takes the pointer argument, skips the current operator
and returns pointer value.
*/
char *skipop( s )
char *s ;
{
s = skipsp( s );
if(op( *s ))s++ ;
else s = skiptok( s );
s = skipsp( s );
return( s );
}
/*
Skipexpr increments pointer S to the end of the current simple
expression, if a nested expresssion turns up, a recursive call
is made to Skipexpr.
*/
char *skipexpr( s )
char *s ;
{
if(*s == LPAREN)s++ ;
while(!eoe( *s )){
if(*s == LPAREN)s = skipexpr( s );
else s++ ;
}
if(*s == RPAREN)s++ ;
s = skipsp( s );
return( s );
}
/*
This procedures calculates a simple expression and returns the
value.
*/
unsigned calc( val1, op, val2 )
unsigned val1, val2 ;
char op ;
{
switch (op) {
case PLUS : return( val1 + val2 );
case MINUS : return( val1 - val2 );
case MULT : return( val1 * val2 );
case DIV : return( val1 / val2 );
case OR : return( val1 | val2 );
case AND : return( val1 & val2 );
case XOR : return( val1 ^ val2 );
case MOD : return( val1 % val2 );
case SHL : return( val1 << val2 );
case SHR : return( val1 >> val2 );
default : aerror(3);return( 0 );
}
}
/*
Here we return a single byte representation of the current operator,
this is used in the switch statement in CALC.
*/
char gettop( s )
char *s ;
{
char operator[80] ;
s = skipsp( s );
if(op( *s ))return( *s );
else {
token( s, operator );
if(strcmp( operator, TXAND ) == 0)return( AND );
if(strcmp( operator, TXXOR ) == 0)return( XOR );
if(strcmp( operator, TXSHL ) == 0)return( SHL );
if(strcmp( operator, TXSHR ) == 0)return( SHR );
if(strcmp( operator, TXMOD ) == 0)return( MOD );
if(strcmp( operator, TXOR ) == 0)return( OR );
}
aerror(4);
return( FALSE );
}
/*
Copy next token from line S to buffer TO
*/
token( s, to )
char *s, *to ;
{
char *p, c ;
s = skipsp( s );
p = s ; s++ ;
while(!spc( *s ) && !op( *s ) && !eoe( *s ) && *s != LPAREN)s++ ;
c = *s ; *s = EOL ;
strcpy( to, p );
*s = c ;
}
pack( s )
char *s ;
{
char c, *p ;
for( c = 0 ; c < 7 ; c++ ){
if(*s == EOL)break ;
s++ ;
}
if(*s++ != EOL){
p = s ;
while(*p != EOL)p++ ;
p-- ; *s++ = *p ;
*s = EOL ;
}
}
/*
Return TRUE if next token is a unary operator, else FALSE.
*/
char isunary( s )
char *s ;
{
char opr[80] ;
s = skipsp( s );
switch (*s) {
case MINUS :
case PLUS :
case NOT : return( *s );
}
token( s, opr );
if(strcmp( opr, TXNOT ) == 0)return( SNOT );
else return( FALSE );
}
/*
Return the binary value of the token at S, this may be a numeric
constant or a symbol in the symbol table.
*/
unsigned gettok( s )
char *s ;
{
char operand[80] ;
s = skipsp( s );
token( s, operand );
if(isdigit(operand[0]))return( cbin( operand ) );
else if(operand[0] == ASCII)return( operand[1] );
else { pack( operand );
return( lookup( operand ) );
}
}
unsigned lookup( s )
char *s ;
{
return( 0 );
}
scp( to, from )
char *to, *from ;
{
char c ;
c = *from++ ;
while(c != EOL)
{ *to++ = c ;
c = *from++ ;
}
}
reverse( s )
char s[];
{
int c, i, j ;
for(i = 0, j = strlen( s ) - 1 ; i < j ; i++, j-- )
{ c = s[i] ; s[i] = s[j] ; s[j] = c ; }
}
b2asc( c )
char c ;
{
c += '0' ;
if